-
Notifications
You must be signed in to change notification settings - Fork 47.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Fiber] Refactor Commit Phase into Separate Functions for Before Mutation/Mutation/Layout #31930
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Comparing: d8b903f...e953c4e Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: Expand to show
|
@@ -744,6 +744,7 @@ describe('ReactDeferredValue', () => { | |||
</Container>, | |||
); | |||
// We should switch to pre-rendering the new preview. | |||
await waitForPaint([]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This happens because the requestPaint()
is now unconditional even if there weren't any effects. Which doesn't really hurt anything since it's actually a noop in anything but tests and should probably go away.
@@ -3460,7 +3471,8 @@ function commitRootImpl( | |||
} | |||
} | |||
|
|||
onCommitRootDevTools(finishedWork.stateNode, renderPriorityLevel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is a bit strange because the profiler in devtools tracks the priority level that the commit phase is running in rather than what priority was rendered and then committed. I think the idea is that it would be running in the scheduler priority of the render but that's not necessarily the case for the commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the codes function correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The refactor LGTM but also changing the finishedWork
to cancelPendingCommit
seems sus. Any way you could at least break that change into a separate PR so it's easier to revert if there's an unexpected issue?
@@ -1839,9 +1841,6 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber { | |||
} | |||
} | |||
|
|||
root.finishedWork = null; | |||
root.finishedLanes = NoLanes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should root.cancelPendingCommit
and timeoutHandle
get reset?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They do get reset right below here as they're cancelled.
'bug in React.', | ||
); | ||
} | ||
} | ||
} | ||
root.finishedWork = null; | ||
root.finishedLanes = NoLanes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should root.cancelPendingCommit
and timeoutHandle
get reset?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
root.cancelPendingCommit
gets reset in the beginning of commitRoot
. timeoutHandle
gets reset in the beginning of commitRootWhenReady
.
Which is really just right at the beginning of the callback that was pending.
The idea is that it's reset right after the callback is fired, at the very beginning, since it's no longer pending. Or it gets reset when it's cancelled.
} | ||
} | ||
flushMutationEffects(root, finishedWork, lanes); | ||
flushLayoutEffects( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be nice to move the before mutation logic above to flushBeforeMutationEffects
to match these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These won't remain exactly like this once they get split out into the async ones and there's more phases a bit in motion. For now it's to make it clear which parts are sync and which parts are async.
Once that settles we can see where we end up.
const prevTransition = ReactSharedInternals.T; | ||
const previousUpdateLanePriority = getCurrentUpdatePriority(); | ||
setCurrentUpdatePriority(DiscreteEventPriority); | ||
ReactSharedInternals.T = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to set the priority here? Is this just so the reactor is more 1-1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea it's mainly to keep it 1-1. Since this is a user space callback you could have a setState in here such as updating an error dialog.
Therefore this must have some semantic. It used to be Discrete based on how it was factored but it makes sense that it would be.
Whether it always should be anyway is an interesting question though. It really shouldn't be possible to run a commit inside a startTransition so I'm not sure how it could ever be anything else.
We're already setting the update priority around user space code.
The execution scope of the commit isn't as useful for profiling information.
This aligns it with passive effects. We can cancel these using the timeoutHandle or cancelPendingCommit. We should never run a commit function that was cancelled. We can check these to determine whether there are any pending commits.
Because ReactFiberLane is imported for its constants it cannot depend on the config.
facd6aa
to
f472472
Compare
This part gives me a bit more confident that it'll work correctly with the async gaps inserted. I think we'll just have to revert this whole PR if something goes wrong. Which is why I wanted to land this piece as early as possible. |
There's still an outstanding thing to resolve. It doesn't show up in this PR since it's still sync but once async gaps are inserted there could be setStates/renders that in the gap that needs to model a pending commit similar to passive but it's more like Execution Environment in that all sync updates need to be deferred until this commit finishes. |
Stacked on #31922.
This is doing some general clean up to be able to split the commit root three phases into three separate async steps.